﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DataConvertTool;
namespace 串口通信监控与设备连接心跳实现
{
    public partial class Form1 : Form
    {

        SerialPort serialPort1 = new SerialPort();
        ConcurrentQueue<byte[]> receiveBytesQueue = new ConcurrentQueue<byte[]>();
        bool isSend = false;
        bool isReceiveData = false;


        public Form1()
        {
            InitializeComponent();
            serialPort1.DataReceived += SerialPort1_DataReceived;
            FindPortNameList();//寻找串口列表


        }


        /// <summary>
        /// 将数据存入队列
        /// </summary>
        /// <param name="bytes"></param>
        private void EnqueueData(byte[] bytes)
        {
            try
            {
                receiveBytesQueue.Enqueue(bytes);
            }
            catch (Exception ex)
            {

            }
        }


        List<byte> allBytes = new List<byte>();

        /// <summary>
        /// 处理接收数据
        /// </summary>
        private void DealReceiveData()
        {
            while (true)
            {
                try
                {
                    int count = receiveBytesQueue.Count;
                    bool result = false;
                    byte[] byteList = null;
                    for (int i = 0; i < count; i++)
                    {
                        result = receiveBytesQueue.TryDequeue(out byteList);
                        if (result)
                        {
                            allBytes.AddRange(byteList);

                            //寻找结束符的位置
                            bool getEndCharIndexResult = false;
                            int endCharIndex = GetEndCharIndex(allBytes, out getEndCharIndexResult);
                            bool getStartCharIndexResult = false;
                            int startCharIndex = GetStartCharIndex(allBytes, out getStartCharIndexResult);


                            if (getEndCharIndexResult && getStartCharIndexResult)//找到心跳包的结束符和起始符
                            {
                                isReceiveData = true;
                                int cout = endCharIndex - startCharIndex + 1; //#111\r\n
                                allBytes.RemoveRange(startCharIndex, cout); // 移除起始符和结束符之间的数据(这个之间的数据是心跳数据)
                                DisplayData(allBytes);
                                allBytes.Clear();//清除接收的数据
                            }
                        }
                    }

                }
                catch
                {

                }
            }
        }

        private void DisplayData(string str)
        {

            this.Invoke(new Action(() =>
            {

                richTextBox_Receive.AppendText(str + "\n");
            }));
        }

        /// <summary>
        /// 根据结束符截取数据并显示数据
        /// </summary>
        /// <param name="allBytes"></param>
        /// <param name="endCharIndex"></param>
        private void DisplayData(List<byte> allBytes)
        {
            string errorMsg = string.Empty;
            string str = Encoding.ASCII.GetString(allBytes.ToArray());
            this.Invoke(new Action(() =>
            {

                richTextBox_Receive.AppendText(str + "\n");
            }));
        }
        /// <summary>
        /// 寻找心跳包的起始字符
        /// </summary>
        /// <param name="allBytes"></param>
        /// <param name="Result"></param>
        /// <returns></returns>
        private int GetStartCharIndex(List<byte> allBytes, out bool Result)
        {
            Result = false;
            byte startChar = 0x23;//起开符号为：#字符

            int startCharIndex = allBytes.IndexOf(startChar);
            if (startCharIndex > 0)
            {
                Result = true;
                return startCharIndex;//返回结束符的位置
            }
            else
            {
                return -1;
            }
        }




        /// <summary>
        /// 获取0x0a这个索引，并且发送过来的报文以0x0d、0x0a作为结束符
        /// </summary>
        /// <param name="allBytes"></param>
        /// <param name="Result"></param>
        /// <returns></returns>
        private int GetEndCharIndex(List<byte> allBytes, out bool Result)
        {
            Result = false;
            byte endChar1 = 0x0d;//回车
            byte endChar2 = 0x0a;//换行

            int endChar1Index = allBytes.IndexOf(endChar1);
            int endChar2Index = allBytes.IndexOf(endChar2);
            if ((endChar2Index - endChar1Index) == 1 && endChar2Index > 0 && endChar1Index > 0)
            {
                Result = true;
                return endChar2Index;//返回结束符的位置
            }
            else
            {
                return -1;
            }
        }

        private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //Thread.Sleep(100);
            int nums = serialPort1.BytesToRead;
            if (nums > 0)
            {
                byte[] bytes = new byte[nums];
                serialPort1.Read(bytes, 0, nums);//将指定字节数数据存到数组中
                EnqueueData(bytes);//显示数据
            }


        }

        /// <summary>
        /// 寻找串口列表
        /// </summary>
        private void FindPortNameList()
        {
            try
            {
                cbx_PortNameList.Items.Clear();
                string[] portNameList = SerialPort.GetPortNames();//寻找电脑存在的端口
                if (portNameList != null && portNameList.Count() > 0)
                {
                    cbx_PortNameList.Items.AddRange(portNameList);
                    cbx_PortNameList.SelectedIndex = 0;
                }
            }
            catch (Exception)
            {

            }
        }

        /// <summary>
        /// 初始化串口
        /// </summary>
        private void InitialPort()
        {
            serialPort1.BaudRate = 9600;//设置波特率
            serialPort1.DataBits = 8;//设置数据位
            serialPort1.StopBits = StopBits.One;//设置停止位
            serialPort1.Parity = Parity.None;//设置校验位
        }


        /// <summary>
        /// 关闭串口
        /// </summary>
        /// <returns></returns>
        private bool ClosePort()
        {
            bool closeResult = false;
            try
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    if (serialPort1.IsOpen == false)
                    {
                        closeResult = true;
                    }
                }
                else
                {
                    closeResult = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("关闭串口失败");
            }
            return closeResult;
        }


        /// <summary>
        /// 打开串口
        /// </summary>
        /// <returns></returns>
        private bool OpenPort()
        {
            bool openResult = false;
            try
            {
                if (cbx_PortNameList.SelectedIndex >= 0)
                {
                    serialPort1.PortName = cbx_PortNameList.SelectedItem.ToString();
                    InitialPort();
                    if (serialPort1.IsOpen == false)
                    {
                        serialPort1.Open();//打开串口
                        if (serialPort1.IsOpen)
                            openResult = true;
                    }
                    else
                    {
                        serialPort1.Close();//关闭串口
                        serialPort1.Open();//打开串口
                        if (serialPort1.IsOpen)
                            openResult = true;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开串口异常:{ex.Message}");
            }
            return openResult;
        }

        private void btn_Open_Click(object sender, EventArgs e)
        {
            try
            {
                if (btn_Open.Text == "打开")
                {
                    bool result = OpenPort();
                    if (result)
                    {
                        isSend = true;
                        Task.Run(new Action(SendHeartBeat));
                        btn_Open.Text = "关闭";
                        UpdatePortStatus(true);
                    }

                }
                else
                {
                    ClosePort();
                    UpdatePortStatus(false);
                    btn_Open.Text = "打开";
                    isSend = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开串口异常:{ex.Message}");
            }

        }

        /// <summary>
        /// 更新串口打开状态
        /// </summary>
        /// <param name="isOpen"></param>
        private void UpdatePortStatus(bool isOpen)
        {
            if (isOpen)
            {
                toolStripStatusLabel_Port.Text = "串口打开";
                toolStripStatusLabel_Port.BackColor = Color.Lime;
            }
            else
            {
                toolStripStatusLabel_Port.Text = "串口关闭";
                toolStripStatusLabel_Port.BackColor = Color.Red;
            }
        }

        private void SendHeartBeat()
        {

            while (isSend)
            {
                try
                {

                    string sendStr = "heartBeat\r\n";//获取界面的字符串
                    byte[] sendBytes = Encoding.ASCII.GetBytes(sendStr);//将ASCII字符串转成字节数组
                    serialPort1.Write(sendBytes, 0, sendBytes.Length);//发送字节数组

                    DateTime startTime = DateTime.Now;

                    while (true)
                    {
                        DateTime endTime = DateTime.Now;
                        double diffTime = (endTime - startTime).TotalSeconds;
                        if (diffTime > 5)
                        {
                            DisplayData("设备超时");
                            break;
                        }
                        // 接收到设备返回的信息之后会将isReceiveData设置为true
                        if (isReceiveData)
                        {
                            isReceiveData = false;
                            break;
                        }
                        Thread.Sleep(50);
                    }

                }
                catch (Exception ex)
                {
                    MessageBox.Show($"发送数据异常:{ex.Message}");
                }
                Thread.Sleep(2000);
            }

        }

        private void btn_Clear_Click(object sender, EventArgs e)
        {
            tbx_Send.Clear();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Task.Run(DealReceiveData);
        }
    }
}
